﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Collections;

using System.Globalization;

namespace System
{
    /// <summary>
    /// 实体对象操作帮助类
    /// </summary>
    public class CModel
    {
        static Hashtable objects = new Hashtable();

        /// <summary>
        /// 通过反射创建对象（应用反射 + 缓存 + 浅层拷贝）
        /// </summary>
        /// <param name="modelAssemblyName">实体对象程序集名</param>
        /// <param name="modelName">实体对象名</param>
        /// <returns>返回创建的对象</returns>
        public static object CreatObject(string modelAssemblyName, string modelName)
        {
            object result = null;

            lock (objects)
            {
                string key = modelAssemblyName + "." + modelName;

                if (objects == null)
                {
                    objects = new Hashtable();
                }

                if (!objects.ContainsKey(key))
                {
                    result = Assembly.Load(modelAssemblyName).CreateInstance(key);
                    objects.Add(key, ((BaseModel)(result)).Clone(true));
                }
                else
                {
                    result = ((BaseModel)objects[key]).Clone(true);
                }
            }

            return result;
        }

        #region GetProValue

        /// <summary>
        /// 获取对象中属性值
        /// </summary>
        /// <param name="model">待处理对象</param>
        /// <param name="proName">属性名</param>
        /// <returns>返回属性值</returns>
        public static string GetProValue(object model, string proName)
        {
            object result = GetProValue(proName, model);

            if (result != null)
            {
                return result.ToString();
            }
            else
            {
                return string.Empty;
            }
        }

        /// <summary>
        /// 获取对象中属性值
        /// </summary>
        /// <typeparam name="T">值的类型</typeparam>
        /// <param name="proName">属性名</param>
        /// <param name="model">待处理对象</param>
        /// <returns>返回属性值</returns>
        public static T GetProValue<T>(string proName, object model)// where T : BaseModel, new()
        {
            T result = default(T);

            object obj = GetProValue(proName, model);

            if (obj != null)
            {
                result = (T)obj;
            }

            return result;
        }

        /// <summary>
        /// 获取对象中属性值
        /// </summary>
        /// <param name="model">待处理对象</param>
        /// <param name="proInfo">属性</param>
        /// <returns>返回属性值</returns>
        public static object GetProValue(object model, PropertyInfo proInfo)
        {
            object result = null;

            if (proInfo != null)
            {
                result = proInfo.GetValue(model, null);
            }

            return result;
        }

        /// <summary>
        /// 获取对象中属性值
        /// </summary>
        /// <param name="proName">属性名</param>
        /// <param name="model">待处理对象</param>
        /// <returns>返回属性值</returns>
        public static object GetProValue(string proName, object model)
        {
            object result = null;

            PropertyInfo proInfo = CReflection.GetPropertyInfo(model, proName);

            if (proInfo != null)
            {
                result = proInfo.GetValue(model, null);
            }

            return result;
        }

        #endregion

        #region SetProValue

        /// <summary>
        /// 设置对象属性值
        /// </summary>
        /// <param name="model">待处理对象</param>
        /// <param name="proName">属性名</param>
        /// <param name="value">值</param>
        public static void SetProValue(object model, string proName, object value)
        {
            PropertyInfo proInfo = CReflection.GetPropertyInfo(model, proName);
            SetProValue(model, proInfo, value);
        }

        //public static void SetProValue<T>(T model, string proName, object value) where T:BaseModel,new()
        //{
        //    PropertyInfo proInfo = model.GetType().GetProperty(proName); //ReflectionHelper.GetPropertyInfo(model, proName);
        //    //SetProValue<T>(model, proInfo, value);
        //    SetProValueMy(model, proInfo, value);
        //}

        /// <summary>
        /// 设置对象属性值
        /// </summary>
        /// <param name="model">待处理对象</param>
        /// <param name="proInfo">属性</param>
        /// <param name="value">值</param>
        public static void SetProValue(object model, PropertyInfo proInfo, object value)
        {
            if (proInfo != null)
            {
                object oldValue = GetProValue(model, proInfo);

                if (oldValue != null)
                {
                    if (value != null)
                    {
                        if (!oldValue.Equals(value))
                        {
                            SetProValueMy(model, proInfo, value);
                        }
                    }
                    else
                    {
                        SetProValueMy(model, proInfo, value);
                    }
                }
                else
                {
                    if (value != null)
                    {
                        SetProValueMy(model, proInfo, value);
                    }
                }
            }
        }


        protected static void SetProValueMy(object model, PropertyInfo proInfo, object value)
        {
            string fullName = proInfo.PropertyType.FullName;

            if (value == null)
                proInfo.SetValue(model, null, null);
            else if (fullName.Contains("Boolean"))
                proInfo.SetValue(model, Convert.ToBoolean(value, CultureInfo.InvariantCulture), null);
            else if (fullName.Contains("Double"))
                proInfo.SetValue(model, Convert.ToDouble(value, CultureInfo.InvariantCulture), null);
            else if (fullName.Contains("Int32"))
                proInfo.SetValue(model, Convert.ToInt32(value, CultureInfo.InvariantCulture), null);
            else if (fullName.Contains("Single"))
                proInfo.SetValue(model, Convert.ToSingle(value, CultureInfo.InvariantCulture), null);
            else if (fullName.Contains("Guid"))
                proInfo.SetValue(model, new Guid(value.ToString()), null);
            else if (fullName.Contains("Decimal"))
                proInfo.SetValue(model, Convert.ToDecimal(value, CultureInfo.InvariantCulture), null);
            else if (fullName.Contains("DateTime"))
                proInfo.SetValue(model, Convert.ToDateTime(value, CultureInfo.InvariantCulture), null);
            else if (fullName.Contains("String"))
                proInfo.SetValue(model, Convert.ToString(value, CultureInfo.InvariantCulture), null);
            else if (proInfo.PropertyType == typeof(byte[]))
                proInfo.SetValue(model, (byte[])(value), null);
            else
                proInfo.SetValue(model, value, null);


        }

        #endregion

        #region GetModelFieldAttribute

        /// <summary>
        /// 获取Attribute值
        /// </summary>
        /// <typeparam name="T">Attribute值类型</typeparam>
        /// <param name="proInfo">属性</param>
        /// <param name="attributeKey">Attribute名</param>
        /// <returns>Attribute值</returns>
        public static T GetModelFieldAttributeValue<T>(PropertyInfo proInfo, string attributeKey)
        {
            ModelFieldAttribute dataFieldAttribute = GetModelFieldAttribute(proInfo);

            T res = default(T);

            switch (attributeKey.ToUpperInvariant())
            {
                case "dbtype":
                    res = (T)(Object)dataFieldAttribute.DbType;
                    break;
                case "descriprion":
                    res = (T)(Object)dataFieldAttribute.Description;
                    break;
                case "errormessage":
                    res = (T)(Object)dataFieldAttribute.ErrorMessage;
                    break;
                case "fieldtype":
                    res = (T)(Object)dataFieldAttribute.FieldType;
                    break;
                case "idgeneratorname":
                    res = (T)(Object)dataFieldAttribute.IdGeneratorName;
                    break;
                case "isallownull":
                    res = (T)(Object)dataFieldAttribute.IsAllowNull;
                    break;
                case "isdbgenerated":
                    res = (T)(Object)dataFieldAttribute.IsDbGenerated;
                    break;
                case "isforeignkey":
                    res = (T)(Object)dataFieldAttribute.IsForeignKey;
                    break;
                case "iskeyfield":
                    res = (T)(Object)dataFieldAttribute.IsKeyField;
                    break;
                case "isneedrecordmodify":
                    res = (T)(Object)dataFieldAttribute.IsNeedRecordModify;
                    break;
                case "isunique":
                    res = (T)(Object)dataFieldAttribute.IsUnique;
                    break;
                case "name":
                    res = (T)(Object)dataFieldAttribute.Name;
                    break;
                case "size":
                    res = (T)(Object)dataFieldAttribute.Size;
                    break;
                case "type":
                    res = (T)(Object)dataFieldAttribute.Type;
                    break;
                case "validationexpression":
                    res = (T)(Object)dataFieldAttribute.ValidationExpression;
                    break;
            }

            return res;
        }

        /// <summary>
        /// 获取Attribute值
        /// </summary>
        /// <param name="proInfo">属性</param>
        /// <param name="attributeKey">Attribute名</param>
        /// <returns>Attribute值</returns>
        public static object GetModelFieldAttributeValue(PropertyInfo proInfo, string attributeKey)
        {
            return GetModelFieldAttributeValue<object>(proInfo, attributeKey);
        }

        /// <summary>
        /// 获取Attribute值
        /// </summary>
        /// <typeparam name="T">Attribute值类型</typeparam>
        /// <param name="type">对象类型</param>
        /// <param name="proName">属性名</param>
        /// <param name="attributeKey">Attribute名</param>
        /// <returns>Attribute值</returns>
        public static T GetModelFieldAttributeValue<T>(Type type, string proName, string attributeKey)
        {
            PropertyInfo proInfo = CReflection.GetPropertyInfo(type, proName);
            return GetModelFieldAttributeValue<T>(proInfo, attributeKey);
        }

        /// <summary>
        /// 获取Attribute值
        /// </summary>
        /// <typeparam name="T">Attribute值类型</typeparam>
        /// <param name="type">对象类型</param>
        /// <param name="attributeKey">Attribute名</param>
        /// <returns>Attribute值</returns>
        public static T GetModelAttributeValue<T>(Type type, string attributeKey)
        {
            ModelAttribute modelAttribute = CReflection.GetAttribute(type);

            T res = default(T);
            if (modelAttribute != null)
            {
                switch (attributeKey.ToUpperInvariant())
                {
                    case "condition":
                        res = (T)(Object)modelAttribute.Condition;
                        break;
                    case "isneedrecordmodify":
                        res = (T)(Object)modelAttribute.IsNeedRecordModify;
                        break;
                    case "modeltype":
                        res = (T)(Object)modelAttribute.ModelType;
                        break;
                    case "name":
                        res = (T)(Object)modelAttribute.Name;
                        break;
                    case "primarykey":
                        res = (T)(Object)modelAttribute.PrimaryKey;
                        break;
                }
            }
            return res;
        }

        /// <summary>
        /// 获取Attribute值
        /// </summary>
        /// <param name="type">对象类型</param>
        /// <param name="attributeKey">Attribute名</param>
        /// <returns>Attribute值</returns>
        public static object GetModelAttributeValue(Type type, string attributeKey)
        {
            return GetModelAttributeValue<object>(type, attributeKey);
        }

        /// <summary>
        /// 获取Attribute值
        /// </summary>
        /// <typeparam name="T">Attribute值类型</typeparam>
        /// <param name="model">待处理对象</param>
        /// <param name="attributeKey">Attribute名</param>
        /// <returns>Attribute值</returns>
        public static T GetModelAttributeValue<T>(BaseModel model, string attributeKey)
        {
            T res = default(T);

            if (model != null)
            {
                res = GetModelAttributeValue<T>(model.GetType(), attributeKey);
            }

            return res;
        }

        /// <summary>
        /// 获取Attribute值
        /// </summary>
        /// <param name="model">待处理对象</param>
        /// <param name="attributeKey">Attribute名</param>
        /// <returns>Attribute值</returns>
        public static object GetModelAttributeValue(BaseModel model, string attributeKey)
        {
            return GetModelAttributeValue<object>(model, attributeKey);
        }

        /// <summary>
        /// 获取Attribute值
        /// </summary>
        /// <param name="type">对象类型</param>
        /// <param name="proName">属性名</param>
        /// <param name="attributeKey">Attribute名</param>
        /// <returns>Attribute值</returns>
        public static object GetModelFieldAttributeValue(Type type, string proName, string attributeKey)
        {
            return GetModelFieldAttributeValue(type, proName, attributeKey);
        }

        /// <summary>
        /// 获取Attribute值
        /// </summary>
        /// <typeparam name="T">值类型</typeparam>
        /// <param name="model">待处理对象</param>
        /// <param name="proName">属性名</param>
        /// <param name="attributeKey">Attribute名</param>
        /// <returns>Attribute值</returns>
        public static T GetModelFieldAttributeValue<T>(object model, string proName, string attributeKey)
        {
            return GetModelFieldAttributeValue<T>(model.GetType(), proName, attributeKey);
        }

        /// <summary>
        /// 获取Attribute值
        /// </summary>
        /// <param name="model">待处理对象</param>
        /// <param name="proName">属性名</param>
        /// <param name="attributeKey">Attribute名</param>
        /// <returns>Attribute值</returns>
        public static object GetModelFieldAttributeValue(object model, string proName, string attributeKey)
        {
            return GetModelFieldAttributeValue(model.GetType(), proName, attributeKey);
        }

        /// <summary>
        /// 获取ModelFieldAttribute
        /// </summary>
        /// <param name="proInfo">属性</param>
        /// <returns>ModelFieldAttribute</returns>
        public static ModelFieldAttribute GetModelFieldAttribute(MemberInfo proInfo)
        {
            return CReflection.GetModelFieldAttribute(proInfo);
        }

        /// <summary>
        /// 获取ModelFieldAttribute
        /// </summary>
        /// <param name="type">对象类型</param>
        /// <param name="proName">属性名</param>
        /// <returns>ModelFieldAttribute</returns>
        public static ModelFieldAttribute GetModelFieldAttribute(Type type, string proName)
        {
            PropertyInfo proInfo = CReflection.GetPropertyInfo(type, proName);
            return GetModelFieldAttribute(proInfo);
        }

        /// <summary>
        /// 获取ModelFieldAttribute
        /// </summary>
        /// <param name="model">待处理对象</param>
        /// <param name="proName">属性名</param>
        /// <returns>ModelFieldAttribute</returns>
        public static ModelFieldAttribute GetModelFieldAttribute(object model, string proName)
        {
            return GetModelFieldAttribute(model.GetType(), proName);
        }

        /// <summary>
        ///获取属性描述信息  
        /// </summary>
        /// <param name="model">对象</param>
        /// <param name="proName">属性名</param>
        /// <returns>描述信息</returns>
        public static string GetDescription(object model, string proName)
        {
            return GetModelFieldAttribute(model, proName).Description;
        }

        /// <summary>
        /// 获取属性描述信息
        /// </summary>
        /// <param name="modelType">对象类型</param>
        /// <param name="proName">属性名</param>
        /// <returns>描述信息</returns>
        public static string GetDescription(Type modelType, string proName)
        {
            return GetModelFieldAttribute(modelType, proName).Description;
        }

        /// <summary>
        /// 获取属性描述信息
        /// </summary>
        /// <param name="proInfo">属性</param>
        /// <returns>描述信息</returns>
        public static string GetDescription(PropertyInfo proInfo)
        {
            return GetModelFieldAttribute(proInfo).Description;
        }

        #endregion

        /// <summary>
        /// 拷贝对象
        /// </summary>
        /// <param name="sourceM">源对象</param>
        /// <param name="destM"> 目标对象</param>
        public static void ModelCopy(object sourceM, object destM)
        {
            Type objType = destM.GetType();
            PropertyInfo[] objProperties = CReflection.GetPropertyInfos(objType);
            Type objType2 = sourceM.GetType();

            foreach (PropertyInfo modelProperty in objProperties)
            {
                if (modelProperty.CanWrite)
                    modelProperty.SetValue(destM, CReflection.GetPropertyInfo(objType2, modelProperty.Name).GetValue(sourceM, null), null);
            }

        }

        /// <summary>
        /// 拷贝对象
        /// </summary>
        /// <param name="sourceM">源对象</param>
        /// <param name="destM">目标对象</param>
        /// <param name="withoutFields">排除不必拷贝的属性名集合</param>
        public static void ModelCopy(object sourceM, object destM, List<string> withoutFields)
        {
            if (withoutFields == null)
            {
                withoutFields = new List<string>();
            }

            List<string> List = new List<string>();

            foreach (string field in withoutFields)
            {
                List.Add(field.ToUpperInvariant());
            }

            Type objType = destM.GetType();
            PropertyInfo[] objProperties = CReflection.GetPropertyInfos(objType);
            Type objType2 = sourceM.GetType();

            foreach (PropertyInfo modelProperty in objProperties)
            {
                if (!List.Contains(modelProperty.Name.ToUpperInvariant()) && modelProperty.CanWrite)
                    modelProperty.SetValue(destM, CReflection.GetPropertyInfo(objType2, modelProperty.Name).GetValue(sourceM, null), null);
            }

        }

        /// <summary>
        /// 判断对象是否存在某属性
        /// </summary>
        /// <param name="model">待处理对象</param>
        /// <param name="proName">属性名</param>
        /// <returns>返回结果</returns>
        public static bool IsContainsField(object model, string proName)
        {
            List<string> List = new List<string>();

            foreach (string field in (model as BaseModel).Fields)
            {
                List.Add(field.ToUpperInvariant());
            }

            return List.Contains(proName);
        }
        
    }
}
